package ace.tool.generate.code.impl.resolver.scheme.resolver.sdk;

import ace.tool.generate.code.impl.resolver.scheme.model.bo.SdkProject;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.AutoConfigurationImportsInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.ConstantClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.FeignApiClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.FeignClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.FeignScannerClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.SdkAutoConfigClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.SpringFactoriesInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.dto.CommonInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.dto.ProjectInfo;
import ace.tool.generate.code.impl.resolver.scheme.resolver.ProjectInfoResolver;
import ace.tool.generate.code.impl.resolver.scheme.resolver.common.AutoConfigurationImportsInfoResolver;
import ace.tool.generate.code.impl.resolver.scheme.resolver.common.SpringFactoriesInfoResolver;
import ace.tool.generate.code.impl.service.model.input.GenerateInput;
import ace.tool.generate.code.impl.service.model.input.GenerateModelInput;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;

/**
 * @author caspar
 * @date 2023/11/17 10:34
 */
@RequiredArgsConstructor
public class SdkProjectResolver {

  private final GenerateInput input;
  private final ProjectInfo moduleProjectInfo;
  private final CommonInfo commonInfo;

  public SdkProject resolve() {
    ProjectInfo sdkProjectInfo = this.getProjectInfo();
    SdkAutoConfigClassInfo sdkAutoConfigClassInfo = this.getAutoConfigClassInfo(sdkProjectInfo);
    return SdkProject.builder()
        .info(sdkProjectInfo)
        .sdkAutoConfigClassInfo(sdkAutoConfigClassInfo)
        .autoConfigurationImportsFileInfo(
            this.getAutoConfigurationImportsFileInfo(sdkProjectInfo, sdkAutoConfigClassInfo))
        .springFactoriesFileInfo(
            this.getSpringFactoriesFileInfo(sdkProjectInfo, sdkAutoConfigClassInfo))
        .feignApiClassInfos(this.getFeignApiClassInfos(sdkProjectInfo))
        .feignClassInfos(this.getFeignClassInfos(sdkProjectInfo))
        .feignScannerClassInfo(this.getFeignScannerClassInfo(sdkProjectInfo))
        .constantClassInfo(this.getConstantClassInfo(sdkProjectInfo))
        .build();
  }

  private ConstantClassInfo getConstantClassInfo(ProjectInfo sdkProjectInfo) {
    return ConstantClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .sdkProjectInfo(sdkProjectInfo)
        .input(input)
        .build()
        .resolve();
  }

  public FeignScannerClassInfo getFeignScannerClassInfo(ProjectInfo sdkProjectInfo) {
    return FeignScannerClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .sdkProjectInfo(sdkProjectInfo)
        .input(input)
        .build()
        .resolve();
  }

  private List<FeignClassInfo> getFeignClassInfos(ProjectInfo sdkProjectInfo) {
    return input.getModels().stream()
        .map(p -> this.getFeignClassInfo(sdkProjectInfo, p))
        .collect(Collectors.toList());
  }

  private FeignClassInfo getFeignClassInfo(
      ProjectInfo sdkProjectInfo, GenerateModelInput modelInput) {
    return FeignClassInfoResolver.builder()
        .sdkProjectInfo(sdkProjectInfo)
        .modelInput(modelInput)
        .commonInfo(commonInfo)
        .input(input)
        .build()
        .resolve();
  }

  private List<FeignApiClassInfo> getFeignApiClassInfos(ProjectInfo sdkProjectInfo) {
    return input.getModels().stream()
        .map(p -> this.getFeignApiClassInfo(sdkProjectInfo, p))
        .collect(Collectors.toList());
  }

  private FeignApiClassInfo getFeignApiClassInfo(
      ProjectInfo sdkProjectInfo, GenerateModelInput modelInput) {
    return FeignApiClassInfoResolver.builder()
        .sdkProjectInfo(sdkProjectInfo)
        .modelInput(modelInput)
        .commonInfo(commonInfo)
        .input(input)
        .build()
        .resolve();
  }

  public SpringFactoriesInfo getSpringFactoriesFileInfo(
      ProjectInfo sdkProjectInfo, SdkAutoConfigClassInfo sdkAutoConfigClassInfo) {
    return SpringFactoriesInfoResolver.builder()
        .projectRootDir(sdkProjectInfo.getRootDir())
        .classFullNameImports(Arrays.asList(sdkAutoConfigClassInfo.getInfo().getClassFullName()))
        .build()
        .resolve();
  }

  public AutoConfigurationImportsInfo getAutoConfigurationImportsFileInfo(
      ProjectInfo sdkProjectInfo, SdkAutoConfigClassInfo sdkAutoConfigClassInfo) {
    return AutoConfigurationImportsInfoResolver.builder()
        .projectRootDir(sdkProjectInfo.getRootDir())
        .classFullNameImports(Arrays.asList(sdkAutoConfigClassInfo.getInfo().getClassFullName()))
        .build()
        .resolve();
  }

  public SdkAutoConfigClassInfo getAutoConfigClassInfo(ProjectInfo sdkProjectInfo) {
    return AutoConfigClassInfoResolver.builder()
        .commonInfo(commonInfo)
        .sdkProjectInfo(sdkProjectInfo)
        .input(input)
        .build()
        .resolve();
  }

  public ProjectInfo getProjectInfo() {
    return ProjectInfoResolver.builder()
        .projectRootDir(moduleProjectInfo.getRootDir())
        .projectNamePrefix(input.getProjectNamePrefix())
        .projectName(input.getProjectName())
        .projectDisplayName(input.getProjectDisplayName())
        .projectNameSuffix(input.getSdkProjectNameSuffix())
        .build()
        .resolve();
  }
}
